home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / cw_dice.pro < prev    next >
Text File  |  1997-07-08  |  7KB  |  224 lines

  1. ; $Id: cw_dice.pro,v 1.7 1997/01/15 03:11:50 ali Exp $
  2. ;
  3. ; Copyright (c) 1993-1997, Research Systems, Inc.  All rights reserved.
  4. ;    Unauthorized reproduction prohibited.
  5. ;+
  6. ; NAME:
  7. ;    CW_DICE
  8. ;
  9. ; PURPOSE:
  10. ;    CW_DICE is a compound widget that implements a single die.
  11. ;    This widget uses a button with a bitmap label.
  12. ;
  13. ;    The primary purpose of this compound widget is to serve as
  14. ;    a full example of a realistic compound widget for the IDL
  15. ;    User's Guide.
  16. ;
  17. ; CATEGORY:
  18. ;    Compound widgets.
  19. ;
  20. ; CALLING SEQUENCE:
  21. ;    Widget = CW_DICE(Parent)
  22. ;
  23. ; INPUTS:
  24. ;       Parent:      The ID of the parent widget.
  25. ;
  26. ; KEYWORD PARAMETERS:
  27. ;    TUMBLE_CNT: The widget simulates the tumbling of a dice by
  28. ;        changing the bitmap on the dice several times before
  29. ;        settling down to a final value. The number of "tumbles"
  30. ;        is specified by the TUMBLE_CNT keyword. The default is 10.
  31. ;    TUMBLE_PERIOD: The amount of time in seconds between each tumble
  32. ;        of the dice. The default is .05 seconds.
  33. ;    UVALUE:      The user value for the widget.
  34. ;
  35. ; OUTPUTS:
  36. ;       The ID of the created widget is returned.
  37. ;
  38. ; COMMON BLOCKS
  39. ;    CW_DICE_BLK: Used to store dice faces, and the current
  40. ;        random number generator seed for the CW_DICE class.
  41. ;
  42. ; SIDE EFFECTS:
  43. ;    This widget generates event structures containing an extra
  44. ;    field named VALUE giving the final value resulting from a dice roll.
  45. ;    Such events are only sent when the user presses the dice button.
  46. ;
  47. ; PROCEDURE:
  48. ;    The CW_DICE widget consists of a single pushbutton that
  49. ;    displays its current dice value as a bitmask. If the user presses
  50. ;    the button, it tumbles for a moment and then the new value is
  51. ;    displayed and an event is issued.
  52. ;
  53. ;    The current value of the dice is available via the
  54. ;    WIDGET_CONTROL,GET_VALUE command.
  55. ;
  56. ;    The current value can be set by issuing the
  57. ;    WIDGET_CONTROL, SET_VALUE command. If the requested value is
  58. ;    outside the range [1,6], then the dice tumbles to a new value
  59. ;    as if the user had pressed the button, but no event is issued.
  60. ;
  61. ; MODIFICATION HISTORY:
  62. ;    24 October 1993, AB, RSI
  63. ;    16 April 1996, RPM, RSI - Fixed name of WIDGET_TIMER event.
  64. ;                  Fixed check of dice value range.
  65. ;-
  66.  
  67. pro CW_DICE_ROLL, dice, state
  68.   ; Given the state structure from a CW_DICE instance, this routine,
  69.   ; sets it to a new value
  70.  
  71.   COMMON CW_DICE_BLK, seed, faces
  72.  
  73.   IF (state.remaining EQ 0) THEN BEGIN        ; Initial request
  74.     state.remaining = state.tumble_cnt
  75.     state.value = FIX(6 * RANDOMU(seed) + 1)    ; Get final answer up front
  76.   ENDIF 
  77.  
  78.   IF (state.remaining EQ 1) THEN BEGIN
  79.     value = state.value            ; Last time, so use final answer
  80.   ENDIF ELSE BEGIN            ; Not last time, use random value
  81.     value = FIX(6 * RANDOMU(seed) + 1)    ; Intermediate value
  82.     WIDGET_CONTROL, dice, TIMER=state.tumble_period
  83.   ENDELSE
  84.  
  85.   WIDGET_CONTROL, dice, set_value=faces[*,*,value-1]
  86.  
  87.   state.remaining = state.remaining - 1
  88. end
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96. FUNCTION CW_DICE_EVENT, ev
  97.  
  98.   ; Recover the state of this compound widget
  99.   base = ev.handler
  100.   stash = WIDGET_INFO(base, /CHILD)
  101.   WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
  102.  
  103.   ; Roll the die and display the new result.
  104.   CW_DICE_ROLL, stash, state
  105.  
  106.   ; If this invocation is not from the timer, issue an event
  107.   if (TAG_NAMES(ev, /STRUCTURE_NAME) ne 'WIDGET_TIMER') THEN $
  108.     ret = { CW_DICE_EVENT,ID: base,TOP:ev.top,HANDLER:0L,VALUE:state.value } $
  109.   ELSE ret = 0
  110.  
  111.   WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
  112.   RETURN, ret
  113.  
  114. end
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122. pro CW_DICE_SET_VAL, id, value
  123.  
  124.   COMMON CW_DICE_BLK, seed, faces
  125.  
  126.   ; Recover the state of this compound widget
  127.   stash = WIDGET_INFO(id, /CHILD)
  128.   WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
  129.  
  130.   ; If value out of range, roll the dice ourselves
  131.   IF (value lt 1) OR (value gt 6) THEN BEGIN
  132.     CW_DICE_ROLL, stash, state
  133.   ENDIF ELSE BEGIN        ; Use the requested value.
  134.     state.value=value
  135.     WIDGET_CONTROL, stash, SET_VALUE=faces[*,*,value-1]
  136.   endelse
  137.  
  138.   WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
  139. end
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147. function CW_DICE_GET_VAL, id
  148.  
  149.   ; Recover the state of this compound widget
  150.   stash = WIDGET_INFO(id, /CHILD)
  151.   WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
  152.  
  153.   ret = state.value
  154.  
  155.   WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
  156.   return, ret
  157. end
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166. function CW_DICE, parent, value, UVALUE=uvalue, TUMBLE_CNT=tumble_cnt, $
  167.     TUMBLE_PERIOD=tumble_period
  168.  
  169.   COMMON CW_DICE_BLK, seed, faces
  170.  
  171.   IF NOT (KEYWORD_SET(tumble_cnt))  THEN tumble_cnt=10
  172.   IF (tumble_cnt lt 1) then tumble_cnt = 10
  173.   IF NOT (KEYWORD_SET(tumble_period))  THEN tumble_period=.05
  174.   IF (tumble_period lt 0) then tumble_period = .05
  175.   IF NOT (KEYWORD_SET(uvalue))  THEN uvalue=0
  176.  
  177.   on_error,2              ;Return to caller if an error occurs
  178.  
  179.  
  180.   ; Generate the die faces. Each bitmap is 32x32 bits, 4x32 bytes, or 1x32
  181.   ; longwords. This completely non-obvious computation was derived by
  182.   ; using the X Window bitmap program to obtain the bitmaps. Then, I used the
  183.   ; READ_X11_BITMAP program to read them into IDL and did some analysis
  184.   ; to convert them into a programmatically generated longword array.
  185.   ; The final step is to cast the longword array into the 6 byte arrays.
  186.   faces = lonarr(192)
  187.   i4=indgen(4)+1
  188.   s5=[0,5]
  189.   pos=[13, 77, 141, 36, 54, 67, 87, 100, 118, 131, 151, 164, 182]
  190.   v1=['c00300'x,'c00300'x,'c00300'x,'e0010000'x,'8007'x,'f0000000'x,'f'x, $
  191.       'e0018007'x,'e0018007'x,'f000000f'x,'f000000f'x,'f0c0030f'x,'f0c0030f'x]
  192.   v2=['e00700'x,'e00700'x,'e00700'x,'f0030000'x,'c00f'x,'f8010000'x,'801f'x, $
  193.       'f003c00f'x,'f003c00f'x,'f801801f'x,'f801801f'x,'f8e1871f'x,'f8e1871f'x]
  194.   for i = 0, n_elements(pos)-1 do begin
  195.     faces[s5+pos[i]] = v1[i]
  196.     faces[i4+pos[i]] = v2[i]
  197.   endfor
  198.   faces = byte(faces,0,4,32,6)
  199.   BYTEORDER, faces, /HTONL        ; Little endian machines need swap
  200.  
  201.   ; Use RANDOMU to pick the initial value of the die, unless the user
  202.   ; provided one.
  203.   if (n_elements(value) eq 0) then value = fix(6 * randomu(seed) + 1)
  204.  
  205.   ; The state of this compound widget:
  206.   ;    - Its currently displayed value.
  207.   ;    - The number of times the dice should tumble before settling down.
  208.   ;    - The amount of time in seconds in between tumbles.
  209.   ;    - The number of tumbles left before the event should be reported.
  210.   state = { value:value, tumble_cnt:FIX(tumble_cnt), $
  211.         tumble_period:tumble_period, remaining:0 }
  212.  
  213.  
  214.   base = WIDGET_BASE(parent, UVALUE=uvalue, EVENT_FUNC='CW_DICE_EVENT',$
  215.         FUNC_GET_VALUE='CW_DICE_GET_VAL', PRO_SET_VALUE='CW_DICE_SET_VAL')
  216.  
  217.   die = WIDGET_BUTTON(base, value=faces[*,*,value-1])
  218.  
  219.   ; Stash the state
  220.   WIDGET_CONTROL, WIDGET_INFO(base, /CHILD), SET_UVALUE=state, /NO_COPY
  221.  
  222.   return, base
  223. end
  224.